﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;

using dotNails.Util;
using dotNails.CodeGen.Models;
using dotNails.CodeGen.Util;
using System.Xml.Linq;
using System.Collections;
using EnvDTE;
using System.Collections.ObjectModel;

namespace dotNails.UI {
	/// <summary>
	/// Interaction logic for DBManager.xaml
	/// </summary>
	public partial class RemoveTables : UserControl, IChildUserControl {
		private DbmlData _dbml;
		private IUserControlParent _parent;
		private bool _settingSelectAllTables = false;
		private bool _settingSelectAllViews = false;
		private bool _settingSelectAllProcs = false;

		public RemoveTables(IUserControlParent parent, DbmlData dbml) {
			InitializeComponent();
			_parent = parent;
			_dbml = dbml;
			TitleBar.Text = "Remove from " + _dbml.Name;
		}

		//private void Window_Loaded(object sender, RoutedEventArgs e) {
		public void Display() {
			// List the tables from the dbml
			List<dotNails.CodeGen.Models.Table> tables = _dbml.DB.Tables;
			Tables.ItemsSource = tables;
			Tables.SelectedIndex = -1;
		}

		void btnBack_Click(object sender, RoutedEventArgs e) {
			// Find all dbmls in the solution
			List<DbmlData> dbmls = AddInUtil.GetAllDBMLsInSolution(_parent.DTE);

			UserControl previousUserControl = new DatabaseList(_parent, dbmls);
			_parent.LoadUserControl(previousUserControl);
		}

		private void tabTables_GotFocus(object sender, RoutedEventArgs e) {
			ToggleSelectAllVisibility(RemoveTablesTabs.Tables);
			if (Tables.Items.Count <= 0) {
				LoadTables();
			}
		}

		private void LoadTables() {
			ObservableCollection<dotNails.CodeGen.Models.Table> tables = new ObservableCollection<dotNails.CodeGen.Models.Table>(_dbml.DB.Tables);

			Tables.SelectedIndex = -1;
			Tables.ItemsSource = tables;
		}

		private void ClearTables() {
			Tables.SelectedIndex = -1;
			Tables.ItemsSource = null;
			Tables.Items.Clear();
		}

		private void tabViews_GotFocus(object sender, RoutedEventArgs e) {
			ToggleSelectAllVisibility(RemoveTablesTabs.Views);
			if (Views.Items.Count <= 0) {
				LoadViews();
			}
		}

		private void LoadViews() {
			// Whip up an anonymous typed List
			var view = new { Name = "" };
			var views = (new[] { view }).ToList();
			views.RemoveAt(0);

			views.Add(new { Name = "View" });
			views.Add(new { Name = "View2" });
			views.Add(new { Name = "View3" });

			Views.SelectedIndex = -1;
			Views.ItemsSource = views;
		}

		private void ClearViews() {
			Views.SelectedIndex = -1;
			Views.ItemsSource = null;
			Views.Items.Clear();
		}

		private void tabStoredProcs_GotFocus(object sender, RoutedEventArgs e) {
			ToggleSelectAllVisibility(RemoveTablesTabs.Procs);
			if (StoredProcs.Items.Count <= 0) {
				LoadStoredProcs();
			}
			//busyAnimation.Visibility = busyAnimation.Visibility == Visibility.Visible ? Visibility.Hidden : Visibility.Visible;
		}

		private void LoadStoredProcs() {
			ObservableCollection<dotNails.CodeGen.Models.Function> smoProcs = new ObservableCollection<dotNails.CodeGen.Models.Function>(_dbml.DB.Functions);

			StoredProcs.SelectedIndex = -1;
			StoredProcs.ItemsSource = smoProcs;
			busyAnimation.Visibility = Visibility.Hidden;
		}

		private void ClearStoredProcs() {
			StoredProcs.SelectedIndex = -1;
			StoredProcs.ItemsSource = null;
			StoredProcs.Items.Clear();
		}

		void btnRemove_Click(object sender, RoutedEventArgs e) {
			try {
				bool somethingChanged = false;

				// Get the list of removed dbml tables and remove them from the dbml
				foreach (dotNails.CodeGen.Models.Table dbmlTable in Tables.SelectedItems) {
					dotNails.CodeGen.Models.Table selectedTable = _dbml.DB.Tables.Find(t => t.Name == dbmlTable.Name);
					if (selectedTable != null) {
						somethingChanged = true;
						_dbml.DB.Tables.Remove(selectedTable);
					}
				}

				// Get the list of removed dbml procs and remove them from the dbml
				foreach (dotNails.CodeGen.Models.Function dbmlFunction in StoredProcs.SelectedItems) {
					dotNails.CodeGen.Models.Function selectedFunction = _dbml.DB.Functions.Find(f => f.Name == dbmlFunction.Name);
					if (selectedFunction != null) {
						somethingChanged = true;
						_dbml.DB.Functions.Remove(selectedFunction);
					}
				}

				if (_dbml.DB.Tables.Count > 0) {
					// Delete any relationships linking an existing table to a table being removed
					foreach (dotNails.CodeGen.Models.Table removedDbmlTable in Tables.SelectedItems) {
						foreach (Association association in removedDbmlTable.Type.Associations) {
							foreach (dotNails.CodeGen.Models.Table remainingTable in _dbml.DB.Tables) {
								Association linkedAssociation = remainingTable.Type.Associations.Find(a => a.Name == association.Name);
								if (linkedAssociation != null) {
									somethingChanged = true;
									remainingTable.Type.Associations.Remove(linkedAssociation);
								}
							}
						}
					}
				}

				if (somethingChanged) {
					AddInUtil.CheckFileOutOfSourceControl(_parent.DTE, _dbml.FilePath);

					// Write out the dbml
					XElement xml = _dbml.SerializeToXml();
					xml.Save(_dbml.FilePath);

					// TODO: Maintain dbml.layout.cs file for all location info for existing tables

					// Execute the custom tool for the dbml
					_parent.RunCustomToolOnFile(_dbml.FilePath);
				}
			}
			catch (Exception ex) {
				LogUtil.EventLogMessage(ex.Message, ex.InnerException, ex.StackTrace);
			}

			//_parent.Close();
			ReloadTabs();
		}

		private void ReloadTabs() {
			if (tabTables.IsSelected) {
				LoadTables();
				ClearViews();
				ClearStoredProcs();
			}
			else if (tabViews.IsSelected) {
				LoadViews();
				ClearTables();
				ClearStoredProcs();
			}
			else if (tabStoredProcs.IsSelected) {
				LoadStoredProcs();
				ClearTables();
				ClearViews();
			}
		}

		private void chkSelectAllTables_Click(object sender, RoutedEventArgs e) {
			// The checkbox will immediately change its state when clicked, so coming in checked, means it was just checked
			if (!chkSelectAllTables.IsChecked.Value) {
				// Checkbox was deselected, so unselect all items in listbox
				Tables.UnselectAll();
			}
			else {
				_settingSelectAllTables = true;
				Tables.SelectAll();
				_settingSelectAllTables = false;
			}
		}

		private void Tables_SelectionChanged(object sender, RoutedEventArgs e) {
			if (!_settingSelectAllTables && chkSelectAllTables.IsChecked.Value) {
				chkSelectAllTables.IsChecked = false;
			}
		}

		private void chkSelectAllViews_Click(object sender, RoutedEventArgs e) {
			// The checkbox will immediately change its state when clicked, so coming in checked, means it was just checked
			if (!chkSelectAllViews.IsChecked.Value) {
				// Checkbox was deselected, so unselect all items in listbox
				Views.UnselectAll();
			}
			else {
				_settingSelectAllViews = true;
				Views.SelectAll();
				_settingSelectAllViews = false;
			}
		}

		private void Views_SelectionChanged(object sender, RoutedEventArgs e) {
			if (!_settingSelectAllViews && chkSelectAllViews.IsChecked.Value) {
				chkSelectAllViews.IsChecked = false;
			}
		}

		private void chkSelectAllProcs_Click(object sender, RoutedEventArgs e) {
			// The checkbox will immediately change its state when clicked, so coming in checked, means it was just checked
			if (!chkSelectAllProcs.IsChecked.Value) {
				// Checkbox was deselected, so unselect all items in listbox
				StoredProcs.UnselectAll();
			}
			else {
				_settingSelectAllProcs = true;
				StoredProcs.SelectAll();
				_settingSelectAllProcs = false;
			}
		}

		private void Procs_SelectionChanged(object sender, RoutedEventArgs e) {
			if (!_settingSelectAllProcs && chkSelectAllProcs.IsChecked.Value) {
				chkSelectAllProcs.IsChecked = false;
			}
		}

		private void ToggleSelectAllVisibility(RemoveTablesTabs selectedTab) {
			switch (selectedTab) {
				case RemoveTablesTabs.Tables:
					chkSelectAllTables.Visibility = Visibility.Visible;
					chkSelectAllViews.Visibility = Visibility.Hidden;
					chkSelectAllProcs.Visibility = Visibility.Hidden;
					break;
				case RemoveTablesTabs.Views:
					chkSelectAllTables.Visibility = Visibility.Hidden;
					chkSelectAllViews.Visibility = Visibility.Visible;
					chkSelectAllProcs.Visibility = Visibility.Hidden;
					break;
				case RemoveTablesTabs.Procs:
					chkSelectAllTables.Visibility = Visibility.Hidden;
					chkSelectAllViews.Visibility = Visibility.Hidden;
					chkSelectAllProcs.Visibility = Visibility.Visible;
					break;
			}
		}

	}

	public enum RemoveTablesTabs {
		Tables,
		Views,
		Procs
	}
}